//
// Created by antler on 2018/12/7.
//

#include "lprefix.h"

#include <string>

#include "lua.hpp"
#include "luaext.hpp"

#include "log.h"
#include "GlobalMacros.h"

#include "Color3B.h"
#include "luaext/color3f/Color3F.h"

static int color3b_constructor(lua_State *L) {
    Color3B *ret = nullptr;

    int argc = lua_gettop(L) - 1;
    if (argc == 0) {
        ret = Color3B::create();
    } else if (argc == 1) {
        int type = lua_type(L, 2);
        switch (type) {
            case LUA_TNUMBER: {
                int rgb = luaL_checkint(L, 2);
                ret = Color3B::createWith(rgb);
                break;
            }
            case LUA_TSTRING: {
                const char *rgb = lua_tostring(L, 2);
                ret = Color3B::createWith(rgb);
                break;
            }
            case LUA_TUSERDATA: {
                tolua_Error tolua_err;
                if (tolua_isusertype(L, 2, USERTYPE_COLOR3B, LUA_TNIL, &tolua_err)) {
                    Color3B *obj = (Color3B *) (tolua_tousertype(L, 2, nullptr));
                    if (obj) {
                        ret = Color3B::createWith(*obj);
                    }
                } else if (tolua_isusertype(L, 2, USERTYPE_COLOR3F, LUA_TNIL, &tolua_err)) {
                    Color3F *obj = (Color3F *) (tolua_tousertype(L, 2, nullptr));
                    if (obj) {
                        ret = Color3B::createWith(*obj);
                    }
                }
                break;
            }
        }
    } else if (argc == 3) {
        int r = luaL_checkint(L, 2);
        int g = luaL_checkint(L, 3);
        int b = luaL_checkint(L, 4);
        ret = Color3B::createWith(r, g, b);
    }

    if (ret) {
        LOGV("color3b:constructor self:%p", ret);
        tolua_pushusertype_and_takeownership(L, ret, USERTYPE_COLOR3B);
    } else {
        lua_pushnil(L);
    }
    return 1;
}

static int color3b_destructor(lua_State *L) {
    Color3B *self = (Color3B *) tolua_tousertype(L, 1, 0);
    LOGV("color3b:destructor self:%p", self);
    SAFE_DELETE(self);
    return 0;
}

static int color3b_tostring(lua_State *L) {
    Color3B *self = (Color3B *) toluahelper_tousertype(L, 1, USERTYPE_COLOR3B, nullptr);
    if (self) {
        lua_pushfstring(L, "%s(%d, %d, %d)", tolua_typename(L, 1), self->r, self->g, self->b);
    } else {
        lua_pushfstring(L, "class: %p", lua_topointer(L, 1));
    }
    return 1;
}

static int color3b_toInt(lua_State *L) {
    Color3B *self = (Color3B *) toluahelper_tousertype(L, 1, USERTYPE_COLOR3B, nullptr);
    if (!self) {
        tolua_error(L, "[no object] in function 'toInt'", nullptr);
    }
    lua_pushinteger(L, self->toInt());
    return 1;
}

static int color3b_toString(lua_State *L) {
    Color3B *self = (Color3B *) toluahelper_tousertype(L, 1, USERTYPE_COLOR3B, nullptr);
    if (!self) {
        tolua_error(L, "[no object] in function 'toString'", nullptr);
    }
    lua_pushstring(L, self->toString().c_str());
    return 1;
}

static const luaL_Reg funcs[] = {
        {".call",      color3b_constructor},
        {"__tostring", color3b_tostring},
        {"toInt",      color3b_toInt},
        {"toString",   color3b_toString},
        {nullptr,      nullptr}
};


static int get_r(lua_State *L) {
    Color3B *self = (Color3B *) tolua_tousertype(L, 1, nullptr);
    if (!self) {
        tolua_error(L, "[no object] in field 'r'", nullptr);
    }
    lua_pushinteger(L, self->r);
    return 1;
}

static int set_r(lua_State *L) {
    Color3B *self = (Color3B *) tolua_tousertype(L, 1, nullptr);
    if (!self) {
        tolua_error(L, "[no object] in field 'r'", nullptr);
    }
    self->r = luaL_checkinteger(L, 2);
    return 0;
}

static int get_g(lua_State *L) {
    Color3B *self = (Color3B *) tolua_tousertype(L, 1, nullptr);
    if (!self) {
        tolua_error(L, "[no object] in field 'g'", nullptr);
    }
    lua_pushinteger(L, self->g);
    return 1;
}

static int set_g(lua_State *L) {
    Color3B *self = (Color3B *) tolua_tousertype(L, 1, nullptr);
    if (!self) {
        tolua_error(L, "[no object] in field 'g'", nullptr);
    }
    self->g = luaL_checkinteger(L, 2);
    return 0;
}

static int get_b(lua_State *L) {
    Color3B *self = (Color3B *) tolua_tousertype(L, 1, nullptr);
    if (!self) {
        tolua_error(L, "[no object] in field 'b'", nullptr);
    }
    lua_pushinteger(L, self->b);
    return 1;
}

static int set_b(lua_State *L) {
    Color3B *self = (Color3B *) tolua_tousertype(L, 1, nullptr);
    if (!self) {
        tolua_error(L, "[no object] in field 'b'", nullptr);
    }
    self->b = luaL_checkinteger(L, 2);
    return 0;
}

LUAMOD_API int luaopen_color3b(lua_State *L) {
    tolua_open(L);

    tolua_module(L, nullptr, 0);
    tolua_beginmodule(L, nullptr);
    {
        tolua_usertype(L, USERTYPE_COLOR3B);
        tolua_cclass(L, CLASSNAME_COLOR3B, USERTYPE_COLOR3B, "", color3b_destructor);

        tolua_beginmodule(L, CLASSNAME_COLOR3B);
        {
            toluahelper_setfunc(L, funcs);

            TOLUAHELPER_CLASS_VARIABLE(L, r);
            TOLUAHELPER_CLASS_VARIABLE(L, g);
            TOLUAHELPER_CLASS_VARIABLE(L, b);
        }
        tolua_endmodule(L);
    }
    tolua_endmodule(L);
    return 0;
}